#!/usr/bin/env python3
"""
用户认证路由
"""

import os
from datetime import datetime, timedelta, timezone
from typing import Any
from datetime import datetime, timedelta, timezone


from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
import bcrypt
from sqlalchemy.ext.asyncio.session import AsyncSession
from sqlalchemy.future import select
from sqlalchemy.engine import Result

from app.core.config import settings
from app.database.session import get_db
from app.models.user import User
from app.schemas.user import TokenResponse, UserCreate, UserResponse

# 认证路由
router = APIRouter(tags=["认证"])

# bcrypt配置
BCRYPT_ROUNDS: int = int(os.getenv("BCRYPT_ROUNDS", "12"))  # 加密轮数

# OAuth2密码承载方案
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/token")

# JWT配置
SECRET_KEY: str = settings.JWT_SECRET_KEY
ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = settings.ACCESS_TOKEN_EXPIRE_MINUTES


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """验证密码"""
    return bcrypt.checkpw(plain_password.encode('utf-8'), hashed_password.encode('utf-8'))


def get_password_hash(password: str) -> str:
    """生成密码哈希"""
    salt = bcrypt.gensalt(rounds=BCRYPT_ROUNDS)
    return bcrypt.hashpw(password.encode('utf-8'), salt).decode('utf-8')


async def authenticate_user(db: AsyncSession, username: str, password: str) -> User | None:
    """认证用户"""
    result: Result[tuple[User]] = await db.execute(select(User).filter(User.username == username))
    user: User | None = result.scalars().first()
    if not user:
        return None
    if not verify_password(password, user.password_hash):
        return None
    return user


def create_access_token(data: dict[str, Any], expires_delta: timedelta | None = None) -> str:
    """创建访问令牌"""
    to_encode: dict[str, Any] = data.copy()
    if expires_delta:
        expire = datetime.now(timezone.utc) + expires_delta
    else:
        expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


async def get_current_user(
    db: AsyncSession = Depends(get_db), token: str = Depends(oauth2_scheme)
) -> User:
    """获取当前用户"""
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无效的认证凭据",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str | None = payload.get("sub")
        if username is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception

    result: Result[tuple[User]] = await db.execute(select(User).filter(User.username == username))
    user: User | None = result.scalars().first()
    if user is None:
        raise credentials_exception
    return user


def get_current_active_user(current_user: User = Depends(get_current_user)) -> User:
    """获取当前活跃用户"""
    if not current_user.is_active:
        raise HTTPException(status_code=400, detail="用户未激活")
    return current_user


@router.post("/token", response_model=TokenResponse)
async def login_for_access_token(
    form_data: OAuth2PasswordRequestForm = Depends(), db: AsyncSession = Depends(get_db)
) -> TokenResponse:
    """用户登录获取访问令牌"""
    user = await authenticate_user(db, form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户名或密码错误",
            headers={"WWW-Authenticate": "Bearer"},
        )

    # 更新最后登录时间
    user.last_login = datetime.now(timezone.utc)
    await db.commit()

    # 创建访问令牌
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.username}, expires_delta=access_token_expires
    )

    return TokenResponse(
        access_token=access_token,
        token_type="bearer",
        user=UserResponse.model_validate(user),
    )


@router.post("/register", response_model=UserResponse)
async def register_user(user_data: UserCreate, db: AsyncSession = Depends(get_db)) -> UserResponse:
    """注册新用户"""
    # 检查用户名是否已存在
    result: Result[tuple[User]] = await db.execute(select(User).filter(User.username == user_data.username))
    existing_user: User | None = result.scalars().first()
    if existing_user:
        raise HTTPException(status_code=400, detail="用户名已存在")

    # 创建用户
    hashed_password = get_password_hash(user_data.password)
    user = User()
    user.username = user_data.username
    user.password_hash = hashed_password
    user.name = user_data.name
    user.email = user_data.email
    user.phone = user_data.phone
    user.role = user_data.role

    db.add(user)
    await db.commit()
    await db.refresh(user)

    return UserResponse.model_validate(user)


@router.get("/me", response_model=UserResponse)
async def read_users_me(current_user: User = Depends(get_current_active_user)) -> UserResponse:
    """获取当前用户信息"""
    return UserResponse.model_validate(current_user)


@router.post("/logout")
async def logout() -> dict[str, str]:
    """用户登出"""
    # JWT是无状态的，客户端需要删除令牌
    return {"message": "登出成功"}